package util;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.Cookie;

import sun.rmi.runtime.Log;

public final class RequestUtil {

    public static String filter(String message) {
    	if (message == null)
    		return (null);
    	char content[] = new char[message.length()];
    	message.getChars(0, message.length(), content, 0);
        StringBuilder result = new StringBuilder(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<':
                result.append("&lt;");
                break;
            case '>':
                result.append("&gt;");
                break;
            case '&':
                result.append("&amp;");
                break;
            case '"':
                result.append("&quot;");
                break;
            default:
                result.append(content[i]);
            }
        }
        return (result.toString());
    }

    public static void parseParameters(Map<String,String[]> map, String data, String encoding) {
        if ((data != null) && (data.length() > 0)) {
            byte[] bytes = null;
            try {
                bytes = data.getBytes(B2CConverter.getCharset(encoding));
                parseParameters(map, bytes, encoding);
            } catch (UnsupportedEncodingException uee) {
            }
        }
    }

    public static String URLDecode(String str) {
        return URLDecode(str, null);
    }
    
    public static String URLDecode(String str, String enc) {
        return URLDecode(str, enc, false);
    }
    
    public static String URLDecode(String str, String enc, boolean isQuery) {
        if (str == null)
            return (null);
        byte[] bytes = null;
        try {
            if (enc == null) {
                bytes = str.getBytes(Charset.defaultCharset());
            } else {
                bytes = str.getBytes(B2CConverter.getCharset(enc));
            }
        } catch (UnsupportedEncodingException uee) {
        }
        return URLDecode(bytes, enc, isQuery);
    }

    public static String URLDecode(byte[] bytes, String enc, boolean isQuery) {
        if (bytes == null)
            return null;
        int len = bytes.length;
        int ix = 0;
        int ox = 0;
        while (ix < len) {
            byte b = bytes[ix++];     // Get byte to test
            if (b == '+' && isQuery) {
                b = (byte)' ';
            } else if (b == '%') {
                if (ix + 2 > len) {
                    throw new IllegalArgumentException("requestUtil.urlDecode.missingDigit");
                }
                b = (byte) ((convertHexDigit(bytes[ix++]) << 4)
                            + convertHexDigit(bytes[ix++]));
            }
            bytes[ox++] = b;
        }
        if (enc != null) {
            try {
                return new String(bytes, 0, ox, B2CConverter.getCharset(enc));
            } catch (UnsupportedEncodingException uee) {
                return null;
            }
        }
        return new String(bytes, 0, ox);
    }
    private static byte convertHexDigit( byte b ) {
        if ((b >= '0') && (b <= '9')) return (byte)(b - '0');
        if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10);
        if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10);
        throw new IllegalArgumentException("requestUtil.convertHexDigit.notHex");
    }


    /**
     * Put name and value pair in map.  When name already exist, add value
     * to array of values.
     *
     * @param map The map to populate
     * @param name The parameter name
     * @param value The parameter value
     */
    private static void putMapEntry( Map<String,String[]> map, String name,
            String value) {
        String[] newValues = null;
        String[] oldValues = map.get(name);
        if (oldValues == null) {
            newValues = new String[1];
            newValues[0] = value;
        } else {
            newValues = new String[oldValues.length + 1];
            System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
            newValues[oldValues.length] = value;
        }
        map.put(name, newValues);
    }


    /**
     * Append request parameters from the specified String to the specified
     * Map.  It is presumed that the specified Map is not accessed from any
     * other thread, so no synchronization is performed.
     * <p>
     * <strong>IMPLEMENTATION NOTE</strong>:  URL decoding is performed
     * individually on the parsed name and value elements, rather than on
     * the entire query string ahead of time, to properly deal with the case
     * where the name or value includes an encoded "=" or "&" character
     * that would otherwise be interpreted as a delimiter.
     *
     * NOTE: byte array data is modified by this method.  Caller beware.
     *
     * @param map Map that accumulates the resulting parameters
     * @param data Input string containing request parameters
     * @param encoding The encoding to use; if null, the default encoding is
     * used
     *
     * @exception UnsupportedEncodingException if the requested encoding is not
     * supported.
     */
    public static void parseParameters(Map<String,String[]> map, byte[] data, String encoding) throws UnsupportedEncodingException {
        Charset charset = B2CConverter.getCharset(encoding);
        if (data != null && data.length > 0) {
        	int    ix = 0;
        	int    ox = 0;
        	String key = null;
        	String value = null;
        	while (ix < data.length) {
        		byte c = data[ix++];
        		switch ((char) c) {
        		case '&':
                	value = new String(data, 0, ox, charset);
                    if (key != null) {
                        putMapEntry(map, key, value);
                        key = null;
                    }
                    ox = 0;
                    break;
                case '=':
                    if (key == null) {
                        key = new String(data, 0, ox, charset);
                        ox = 0;
                    } else {
                        data[ox++] = c;
                    }                   
                    break;  
                case '+':
                    data[ox++] = (byte)' ';
                    break;
                case '%':
                    data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4)
                                    + convertHexDigit(data[ix++]));
                    break;
                default:
                    data[ox++] = c;
                }
            }
            //The last value does not end in '&'.  So save it now.
            if (key != null) {
                value = new String(data, 0, ox, charset);
                putMapEntry(map, key, value);
            }
        }

    }
    
    public static Cookie[] parseCookieHeader(String value){
    	if(value == null || (value.length()) < 1){
    		return (new Cookie[0]);
    	}
    	ArrayList cookies = new ArrayList<>();
    	while (value.length() > 0) {
    		int semicolon = value.indexOf(';');
    		if(semicolon < 0){
    			semicolon = value.length();
    			if(semicolon == 0){
    				break;
    			}
    			String token = value.substring(0,semicolon);
    			if(semicolon < value.length()){
    				value = value.substring(semicolon+1);
    			}else{
    				value = "";
    			}
    			try{
    				int equals = token.indexOf('=');
    				if(equals > 0){
    					String name = token.substring(0, equals).trim();
    					String val = token.substring(equals+1).trim();
    					cookies.add(new Cookie(name, val));
    				}
    			}catch(Throwable e){
    				;
    			}
    		}
		}
    	return (Cookie[])cookies.toArray(new Cookie[cookies.size()]);
    }
}
